package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.domain.po.PointsRecord;
import com.tianji.learning.domain.vo.PointsStatisticsVO;
import com.tianji.learning.enums.PointsRecordType;
import com.tianji.learning.mapper.PointsRecordMapper;
import com.tianji.learning.service.IPointsRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 学习积分记录，每个月底清零 服务实现类
 * </p>
 *
 * @author friday
 * @since 2024-01-11
 */
@Service
@RequiredArgsConstructor
public class PointsRecordServiceImpl extends ServiceImpl<PointsRecordMapper, PointsRecord> implements IPointsRecordService {

    private final StringRedisTemplate redisTemplate;

    /**
     * 添加积分记录
     * @param userId
     * @param points
     * @param type
     */
    @Override
    public void addPointsRecord(Long userId, int points, PointsRecordType type) {
        //0.校验
        if (userId == null || points == 0 ){
            return;
        }
        int realPoints = points; //代表实际可以增加的积分

        //1.判断是否有积分上限 type.getMaxPoints()是否大于0
        int maxPoints = type.getMaxPoints();
        if (maxPoints > 0){
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime dayStartTime = DateUtils.getDayStartTime(now);
            LocalDateTime dayEndTime = DateUtils.getDayEndTime(now);
            //2.有上限，查询该用户 该积分类型 今日已得积分 表：points_record 条件：userId type 今天 sum(points)
            //MP实现： select sum（points） as totalPoints from points_record where userId = ? and type = ? and createTime between ? and ?
            QueryWrapper<PointsRecord> wrapper = new QueryWrapper<>();
            wrapper.select("sum(points) as totalPoints");
            wrapper.eq("user_id",userId);
            wrapper.eq("type",type);
            wrapper.between("create_time",dayStartTime,dayEndTime);
            Map<String, Object> map = this.getMap(wrapper);
            int currentPoints = 0; //当前用户 该积分类型 已得积分
            if (map != null){
                BigDecimal totalPoints = (BigDecimal) map.get("totalPoints"); //先强转为BigDecimal，然后在转为int
                currentPoints = totalPoints.intValue();
            }
            //3.判断今日已得积分是否达到上限
            if (currentPoints >= maxPoints){
                //4.今日达到上限  返回
                return ;
            }
            //计算本次实际应该增加多少分
            //没有超出上限则判断是否需要减去积分： 当前积分 + 本次积分  是否超过上限，如果超过则需要减去积分
            if (currentPoints + realPoints > maxPoints){
                realPoints = maxPoints - currentPoints;
            }
        }
        //5.没有上限则直接保存积分记录
        PointsRecord record = new PointsRecord();
        record.setUserId(userId);
        record.setType(type);
        record.setPoints(realPoints);
        this.save(record);

        //6.累加并保存积分总值到redis 采用 zset  用于赛季的排行榜
        LocalDate now = LocalDate.now();
        String format = now.format(DateTimeFormatter.ofPattern("yyyyMM"));
        String key = RedisConstants.POINTS_BOARD_KET_PREFIX + format;
        redisTemplate.opsForZSet().incrementScore(key,userId.toString(),realPoints);
    }

    /**
     * 查询我的今日积分
     * @return
     */
    @Override
    public List<PointsStatisticsVO> queryMyPointsToday() {
        //1.获取用户信息
        Long userId = UserContext.getUser();
        //2.查询用户的积分信息表 points_record
        //2.1 构造查询条件 条件：user_id 今日  按照type分组
        //SELECT TYPE，SUM(points) FROM points_record WHERE user_id = ? AND create_time BETWEEN ? AND ? GROUP BY type
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime dayStartTime = DateUtils.getDayStartTime(now);
        LocalDateTime dayEndTime = DateUtils.getDayEndTime(now);

        //构建查询条件
        QueryWrapper<PointsRecord> wrapper = new QueryWrapper<>();
        wrapper.select("type","sum(points) as userId");  //sum(points)在定义的PointsRecord中没有可以接受的对应字段，所以可以借助userId来接受
        wrapper.eq("user_id",userId);
        wrapper.between("create_time",dayStartTime,dayEndTime);
        wrapper.groupBy("type");
        List<PointsRecord> list = this.list(wrapper);
        if (CollUtils.isEmpty(list)){
            return CollUtils.emptyList();  //list为空，则返回空列表
        }

        //3.封装返回
        List<PointsStatisticsVO> voList = new ArrayList<>();
        for (PointsRecord r : list) {
            PointsStatisticsVO vo = new PointsStatisticsVO();
            vo.setMaxPoints(r.getType().getMaxPoints()); //积分上限
            vo.setType(r.getType().getDesc());  //获取积分方式(返回的值为中文)
            vo.setPoints(r.getUserId().intValue());        //积分值
            voList.add(vo);
        }
        System.out.println("voList = " + voList);
        return voList;
    }

}
